/**
 *  Copyright (C) 2010 dennis zhuang (killme2008@gmail.com)
 *
 *  This library is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published
 *  by the Free Software Foundation; either version 2.1 of the License, or
 *  (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **/
package com.googlecode.aviator;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import com.googlecode.aviator.exception.ExpressionRuntimeException;


/**
 * Compiled expression,encapsulate a java class generated by expression string
 * 
 * @author dennis
 * 
 */
public class ClassExpression implements Expression {
    private final Class<?> clazz;
    private final Method runMethod;


    public ClassExpression(Class<?> clazz) throws NoSuchMethodException, SecurityException {
        super();
        this.clazz = clazz;
        this.runMethod = clazz.getDeclaredMethod("run", Map.class);
        this.runMethod.setAccessible(true);
    }


    /*
     * (non-Javadoc)
     * 
     * @see com.googlecode.aviator.IExpression#execute(java.util.Map)
     */
    public Object execute(Map<String, Object> env) {
        if (env == null) {
            env = new HashMap<String, Object>(AviatorEvaluator.FUNC_MAP);
        }
        else {
            env = new HashMap<String, Object>(env);
            for (String variableName : env.keySet()) {
                if (AviatorEvaluator.FUNC_MAP.containsKey(variableName)) {
                    throw new ExpressionRuntimeException(variableName
                            + " is a function name,please don't use it as variable");
                }
            }
            env.putAll(AviatorEvaluator.FUNC_MAP);
        }
        try {
            return this.runMethod.invoke(null, env);
        }
        catch (InvocationTargetException e) {
            if (e.getCause() != null) {
                throw new ExpressionRuntimeException("Execute expression error", e.getCause());
            }
            else {
                throw new ExpressionRuntimeException("Execute expression error", e);
            }
        }
        catch (Throwable e) {
            throw new ExpressionRuntimeException("Execute expression error", e);
        }
    }


    /*
     * (non-Javadoc)
     * 
     * @see com.googlecode.aviator.IExpression#execute()
     */
    public Object execute() {
        return execute(null);
    }


    /**
     * Get generated java class
     * 
     * @return
     */
    public Class<?> getJavaClass() {
        return this.clazz;
    }
}
